/* ----------
 *	pgstat.h
 *
 *	PostgreSQL 累积统计系统的定义。
 *
 *	Copyright (c) 2001-2022, PostgreSQL Global Development Group
 *
 *	src/include/pgstat.h
 * ----------
 */
#ifndef PGSTAT_H
#define PGSTAT_H

#include "datatype/timestamp.h"
#include "portability/instr_time.h"
#include "postmaster/pgarch.h"	/* 用于 MAX_XFN_CHARS */
#include "utils/backend_progress.h" /* 为了向后兼容 */
#include "utils/backend_status.h"	/* 为了向后兼容 */
#include "utils/relcache.h"
#include "utils/wait_event.h"	/* 为了向后兼容 */


/* ----------
 * 统计文件的路径（相对于安装的 $PGDATA）。
 * ----------
 */
#define PGSTAT_STAT_PERMANENT_DIRECTORY		"pg_stat"
#define PGSTAT_STAT_PERMANENT_FILENAME		"pg_stat/pgstat.stat"
#define PGSTAT_STAT_PERMANENT_TMPFILE		"pg_stat/pgstat.tmp"

/* 默认目录以存储临时统计数据 */
#define PG_STAT_TMP_DIR		"pg_stat_tmp"

/* 统计条目的类型 */
typedef enum PgStat_Kind
{
	/* 使用 0 表示 INVALID，以捕获零初始化的数据 */
	PGSTAT_KIND_INVALID = 0,

	/* 可变编号对象的统计数据 */
	PGSTAT_KIND_DATABASE,		/* 数据库范围的统计信息 */
	PGSTAT_KIND_RELATION,		/* 每个表的统计信息 */
	PGSTAT_KIND_FUNCTION,		/* 每个函数的统计信息 */
	PGSTAT_KIND_REPLSLOT,		/* 每个槽的统计信息 */
	PGSTAT_KIND_SUBSCRIPTION,	/* 每个订阅的统计信息 */

	/* 固定编号对象的统计数据 */
	PGSTAT_KIND_ARCHIVER,
	PGSTAT_KIND_BGWRITER,
	PGSTAT_KIND_CHECKPOINTER,
	PGSTAT_KIND_SLRU,
	PGSTAT_KIND_WAL,
} PgStat_Kind;

#define PGSTAT_KIND_FIRST_VALID PGSTAT_KIND_DATABASE
#define PGSTAT_KIND_LAST PGSTAT_KIND_WAL
#define PGSTAT_NUM_KINDS (PGSTAT_KIND_LAST + 1)

/* track_functions GUC 变量的值 --- 顺序很重要！ */
typedef enum TrackFunctionsLevel
{
	TRACK_FUNC_OFF,
	TRACK_FUNC_PL,
	TRACK_FUNC_ALL
}			TrackFunctionsLevel;

typedef enum PgStat_FetchConsistency
{
	PGSTAT_FETCH_CONSISTENCY_NONE,
	PGSTAT_FETCH_CONSISTENCY_CACHE,
	PGSTAT_FETCH_CONSISTENCY_SNAPSHOT,
} PgStat_FetchConsistency;

/* 用于追踪会话终止原因的值 */
typedef enum SessionEndType
{
	DISCONNECT_NOT_YET,			/* 仍然活跃 */
	DISCONNECT_NORMAL,
	DISCONNECT_CLIENT_EOF,
	DISCONNECT_FATAL,
	DISCONNECT_KILLED
} SessionEndType;

/* ----------
 * 用于计数器的数据类型。
 * ----------
 */
typedef int64 PgStat_Counter;


/* ------------------------------------------------------------
 * 在后端本地内存中保持的结构，在累积计数时使用
 * ------------------------------------------------------------
 */

/* ----------
 * PgStat_FunctionCounts 后端保持的每个函数的实际计数
 *
 * 这个结构应仅包含实际事件计数器，因为我们会将其与零比较
 * 以检测是否有任何待处理的统计信息。
 *
 * 请注意，这里时间计数器采用 instr_time 格式。我们在将待处理的统计数据
 * 刷新为 PgStat_Counter 格式时转换为微秒。
 * ----------
 */
typedef struct PgStat_FunctionCounts
{
	PgStat_Counter f_numcalls;
	instr_time	f_total_time;
	instr_time	f_self_time;
} PgStat_FunctionCounts;

/* ----------
 * PgStat_BackendFunctionEntry 非刷新的函数统计信息。
 * ----------
 */
typedef struct PgStat_BackendFunctionEntry
{
	PgStat_FunctionCounts f_counts;
} PgStat_BackendFunctionEntry;

/*
 * 累积每个函数调用计时统计信息所需的工作状态。
 */
typedef struct PgStat_FunctionCallUsage
{
	/* 链接到函数的哈希表条目（在退出时必须仍然存在！） */
	/* NULL 表示我们未跟踪当前函数调用 */
	PgStat_FunctionCounts *fs;
	/* 函数开始时先前计入函数的总时间 */
	instr_time	save_f_total_time;
	/* 函数开始时的后端范围总时间 */
	instr_time	save_total;
	/* 函数开始时的系统时钟 */
	instr_time	f_start;
} PgStat_FunctionCallUsage;

/* ----------
 * PgStat_BackendSubEntry 非刷新的订阅统计信息。
 * ----------
 */
typedef struct PgStat_BackendSubEntry
{
	PgStat_Counter apply_error_count;
	PgStat_Counter sync_error_count;
} PgStat_BackendSubEntry;


typedef struct PgStat_TableCounts
{
	PgStat_Counter t_numscans;

	PgStat_Counter t_tuples_returned;
	PgStat_Counter t_tuples_fetched;

	PgStat_Counter t_tuples_inserted;
	PgStat_Counter t_tuples_updated;
	PgStat_Counter t_tuples_deleted;
	PgStat_Counter t_tuples_hot_updated;
	bool		t_truncdropped;

	PgStat_Counter t_delta_live_tuples;
	PgStat_Counter t_delta_dead_tuples;
	PgStat_Counter t_changed_tuples;

	PgStat_Counter t_blocks_fetched;
	PgStat_Counter t_blocks_hit;
} PgStat_TableCounts;

/* ----------
 * PgStat_TableStatus			每个后端的每个表状态
 *
 * 许多事件计数器是非事务性的，即我们计算已提交和已中止事务中的事件。对于这些，我们直接在 PgStat_TableStatus 中计数。然而，delta_live_tuples、delta_dead_tuples 和 changed_tuples 必须从事件计数中推导出，并注意事务或子事务是已提交还是已中止。因此，我们还为当前事务中修改的每个表保留一栈每个（子）事务状态记录。在提交或中止时，我们将 tuples_inserted/updated/deleted 传播到父子事务级别，或传播到父 PgStat_TableStatus，视情况而定。
 * ----------
 */
typedef struct PgStat_TableStatus
{
	Oid			t_id;			/* 表的 OID */
	bool		t_shared;		/* 这是一个共享目录吗？ */
	struct PgStat_TableXactStatus *trans;	/* 最低子事务的计数 */
	PgStat_TableCounts t_counts;	/* 要发送的事件计数 */
	Relation	relation;		/* 正在使用此条目的关系 */
} PgStat_TableStatus;

/* ----------
 * PgStat_TableXactStatus		每个表，每个子事务的状态
 * ----------
 */
typedef struct PgStat_TableXactStatus
{
	PgStat_Counter tuples_inserted; /* 在（子）事务中插入的元组 */
	PgStat_Counter tuples_updated;	/* 在（子）事务中更新的元组 */
	PgStat_Counter tuples_deleted;	/* 在（子）事务中删除的元组 */
	bool		truncdropped;	/* 在此（子）事务中截断/删除的关系 */
	/* 截断/删除之前的元组 i/u/d */
	PgStat_Counter inserted_pre_truncdrop;
	PgStat_Counter updated_pre_truncdrop;
	PgStat_Counter deleted_pre_truncdrop;
	int			nest_level;		/* 子事务嵌套级别 */
	/* 指向同一关系的其他结构的链接： */
	struct PgStat_TableXactStatus *upper;	/* 下一个较高的子事务（如果有） */
	PgStat_TableStatus *parent; /* 每个表状态 */
	/* 同一子事务级别的结构链接在这里： */
	struct PgStat_TableXactStatus *next;	/* 同一子事务的下一个 */
} PgStat_TableXactStatus;


/* ------------------------------------------------------------
 * 磁盘和共享内存中的数据结构遵循
 *
 * PGSTAT_FILE_FORMAT_ID 应在这些数据结构中的任何一个变化时进行更改。
 * ------------------------------------------------------------
 */

#define PGSTAT_FILE_FORMAT_ID	0x01A5BCA7

typedef struct PgStat_ArchiverStats
{
	PgStat_Counter archived_count;	/* 归档成功 */
	char		last_archived_wal[MAX_XFN_CHARS + 1];	/* 最近归档的 WAL 文件 */
	TimestampTz last_archived_timestamp;	/* 最近的归档成功时间 */
	PgStat_Counter failed_count;	/* 归档尝试失败 */
	char		last_failed_wal[MAX_XFN_CHARS + 1]; /* 最近失败中涉及的 WAL 文件 */
	TimestampTz last_failed_timestamp;	/* 最近的归档失败时间 */
	TimestampTz stat_reset_timestamp;
} PgStat_ArchiverStats;

typedef struct PgStat_BgWriterStats
{
	PgStat_Counter buf_written_clean;
	PgStat_Counter maxwritten_clean;
	PgStat_Counter buf_alloc;
	TimestampTz stat_reset_timestamp;
} PgStat_BgWriterStats;

typedef struct PgStat_CheckpointerStats
{
	PgStat_Counter timed_checkpoints;
	PgStat_Counter requested_checkpoints;
	PgStat_Counter checkpoint_write_time;	/* 毫秒计时 */
	PgStat_Counter checkpoint_sync_time;
	PgStat_Counter buf_written_checkpoints;
	PgStat_Counter buf_written_backend;
	PgStat_Counter buf_fsync_backend;
} PgStat_CheckpointerStats;

typedef struct PgStat_StatDBEntry
{
	PgStat_Counter n_xact_commit;
	PgStat_Counter n_xact_rollback;
	PgStat_Counter n_blocks_fetched;
	PgStat_Counter n_blocks_hit;
	PgStat_Counter n_tuples_returned;
	PgStat_Counter n_tuples_fetched;
	PgStat_Counter n_tuples_inserted;
	PgStat_Counter n_tuples_updated;
	PgStat_Counter n_tuples_deleted;
	TimestampTz last_autovac_time;
	PgStat_Counter n_conflict_tablespace;
	PgStat_Counter n_conflict_lock;
	PgStat_Counter n_conflict_snapshot;
	PgStat_Counter n_conflict_bufferpin;
	PgStat_Counter n_conflict_startup_deadlock;
	PgStat_Counter n_temp_files;
	PgStat_Counter n_temp_bytes;
	PgStat_Counter n_deadlocks;
	PgStat_Counter n_checksum_failures;
	TimestampTz last_checksum_failure;
	PgStat_Counter n_block_read_time;	/* 微秒计时 */
	PgStat_Counter n_block_write_time;
	PgStat_Counter n_sessions;
	PgStat_Counter total_session_time;
	PgStat_Counter total_active_time;
	PgStat_Counter total_idle_in_xact_time;
	PgStat_Counter n_sessions_abandoned;
	PgStat_Counter n_sessions_fatal;
	PgStat_Counter n_sessions_killed;

	TimestampTz stat_reset_timestamp;
} PgStat_StatDBEntry;

typedef struct PgStat_StatFuncEntry
{
	PgStat_Counter f_numcalls;

	PgStat_Counter f_total_time;	/* 微秒计时 */
	PgStat_Counter f_self_time;
} PgStat_StatFuncEntry;

typedef struct PgStat_StatReplSlotEntry
{
	/*
	 * 在 PG 15 中此字段未使用，但未删除，以避免更改
	 * PGSTAT_FILE_FORMAT_ID。
	 */
	NameData	slotname_unused;
	PgStat_Counter spill_txns;
	PgStat_Counter spill_count;
	PgStat_Counter spill_bytes;
	PgStat_Counter stream_txns;
	PgStat_Counter stream_count;
	PgStat_Counter stream_bytes;
	PgStat_Counter total_txns;
	PgStat_Counter total_bytes;
	TimestampTz stat_reset_timestamp;
} PgStat_StatReplSlotEntry;

typedef struct PgStat_SLRUStats
{
	PgStat_Counter blocks_zeroed;
	PgStat_Counter blocks_hit;
	PgStat_Counter blocks_read;
	PgStat_Counter blocks_written;
	PgStat_Counter blocks_exists;
	PgStat_Counter flush;
	PgStat_Counter truncate;
	TimestampTz stat_reset_timestamp;
} PgStat_SLRUStats;

typedef struct PgStat_StatSubEntry
{
	PgStat_Counter apply_error_count;
	PgStat_Counter sync_error_count;
	TimestampTz stat_reset_timestamp;
} PgStat_StatSubEntry;

typedef struct PgStat_StatTabEntry
{
	PgStat_Counter numscans;

	PgStat_Counter tuples_returned;
	PgStat_Counter tuples_fetched;

	PgStat_Counter tuples_inserted;
	PgStat_Counter tuples_updated;
	PgStat_Counter tuples_deleted;
	PgStat_Counter tuples_hot_updated;

	PgStat_Counter n_live_tuples;
	PgStat_Counter n_dead_tuples;
	PgStat_Counter changes_since_analyze;
	PgStat_Counter inserts_since_vacuum;

	PgStat_Counter blocks_fetched;
	PgStat_Counter blocks_hit;

	TimestampTz vacuum_timestamp;	/* 用户发起的 VACUUM */
	PgStat_Counter vacuum_count;
	TimestampTz autovac_vacuum_timestamp;	/* 自动 VACUUM 发起 */
	PgStat_Counter autovac_vacuum_count;
	TimestampTz analyze_timestamp;	/* 用户发起 */
	PgStat_Counter analyze_count;
	TimestampTz autovac_analyze_timestamp;	/* 自动 VACUUM 发起 */
	PgStat_Counter autovac_analyze_count;
} PgStat_StatTabEntry;

typedef struct PgStat_WalStats
{
	PgStat_Counter wal_records;
	PgStat_Counter wal_fpi;
	uint64		wal_bytes;
	PgStat_Counter wal_buffers_full;
	PgStat_Counter wal_write;
	PgStat_Counter wal_sync;
	PgStat_Counter wal_write_time;
	PgStat_Counter wal_sync_time;
	TimestampTz stat_reset_timestamp;
} PgStat_WalStats;


/*
 * pgstat.c 中的函数
 */

/* 从主进程调用的函数 */
extern Size StatsShmemSize(void);
extern void StatsShmemInit(void);

/* 在服务器启动/关闭期间调用的函数 */
extern void pgstat_restore_stats(void);
extern void pgstat_discard_stats(void);
extern void pgstat_before_server_shutdown(int code, Datum arg);

/* 后台初始化的函数 */
extern void pgstat_initialize(void);

/* 从后端调用的函数 */
extern long pgstat_report_stat(bool force);
extern void pgstat_force_next_flush(void);

extern void pgstat_reset_counters(void);
extern void pgstat_reset(PgStat_Kind kind, Oid dboid, Oid objectid);
extern void pgstat_reset_of_kind(PgStat_Kind kind);

/* stats 访问器 */
extern void pgstat_clear_snapshot(void);
extern TimestampTz pgstat_get_stat_snapshot_timestamp(bool *have_snapshot);

/* helpers */
extern PgStat_Kind pgstat_get_kind_from_str(char *kind_str);
extern bool pgstat_have_entry(PgStat_Kind kind, Oid dboid, Oid objoid);

/* stats_fetch_consistency 的 GUC hook */
extern void assign_stats_fetch_consistency(int newval, void *extra);

/*
 * pgstat_archiver.c 中的函数
 */

extern void pgstat_report_archiver(const char *xlog, bool failed);
extern PgStat_ArchiverStats *pgstat_fetch_stat_archiver(void);


/*
 * pgstat_bgwriter.c中的函数
 */

extern void pgstat_report_bgwriter(void);
extern PgStat_BgWriterStats *pgstat_fetch_stat_bgwriter(void);


/*
 * pgstat_checkpointer.c中的函数
 */

extern void pgstat_report_checkpointer(void);
extern PgStat_CheckpointerStats *pgstat_fetch_stat_checkpointer(void);


/*
 * pgstat_database.c中的函数
 */

extern void pgstat_drop_database(Oid databaseid);
extern void pgstat_report_autovac(Oid dboid);
extern void pgstat_report_recovery_conflict(int reason);
extern void pgstat_report_deadlock(void);
extern void pgstat_report_checksum_failures_in_db(Oid dboid, int failurecount);
extern void pgstat_report_checksum_failure(void);
extern void pgstat_report_connect(Oid dboid);

#define pgstat_count_buffer_read_time(n)							\
	(pgStatBlockReadTime += (n))
#define pgstat_count_buffer_write_time(n)							\
	(pgStatBlockWriteTime += (n))
#define pgstat_count_conn_active_time(n)							\
	(pgStatActiveTime += (n))
#define pgstat_count_conn_txn_idle_time(n)							\
	(pgStatTransactionIdleTime += (n))

extern PgStat_StatDBEntry *pgstat_fetch_stat_dbentry(Oid dbid);

/*
 * pgstat_function.c中的函数
 */

extern void pgstat_create_function(Oid proid);
extern void pgstat_drop_function(Oid proid);

struct FunctionCallInfoBaseData;
extern void pgstat_init_function_usage(struct FunctionCallInfoBaseData *fcinfo,
									   PgStat_FunctionCallUsage *fcu);
extern void pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu,
									  bool finalize);

extern PgStat_StatFuncEntry *pgstat_fetch_stat_funcentry(Oid funcid);
extern PgStat_BackendFunctionEntry *find_funcstat_entry(Oid func_id);


/*
 * pgstat_relation.c中的函数
 */

extern void pgstat_create_relation(Relation rel);
extern void pgstat_drop_relation(Relation rel);
extern void pgstat_copy_relation_stats(Relation dstrel, Relation srcrel);

extern void pgstat_init_relation(Relation rel);
extern void pgstat_assoc_relation(Relation rel);
extern void pgstat_unlink_relation(Relation rel);

extern void pgstat_report_vacuum(Oid tableoid, bool shared,
								 PgStat_Counter livetuples, PgStat_Counter deadtuples);
extern void pgstat_report_analyze(Relation rel,
								  PgStat_Counter livetuples, PgStat_Counter deadtuples,
								  bool resetcounter);

/*
 * 如果启用了统计信息，但待处理的数据尚未准备好，调用
 * pgstat_assoc_relation()来完成这件事。请参阅其注释，了解为何这与pgstat_init_relation()分开执行。
 */
#define pgstat_should_count_relation(rel)                           \
	(likely((rel)->pgstat_info != NULL) ? true :                    \
	 ((rel)->pgstat_enabled ? pgstat_assoc_relation(rel), true : false))

/* 非事务事件计数足够简单，可以内联 */

#define pgstat_count_heap_scan(rel)									\
	do {															\
		if (pgstat_should_count_relation(rel))						\
			(rel)->pgstat_info->t_counts.t_numscans++;				\
	} while (0)
#define pgstat_count_heap_getnext(rel)								\
	do {															\
		if (pgstat_should_count_relation(rel))						\
			(rel)->pgstat_info->t_counts.t_tuples_returned++;		\
	} while (0)
#define pgstat_count_heap_fetch(rel)								\
	do {															\
		if (pgstat_should_count_relation(rel))						\
			(rel)->pgstat_info->t_counts.t_tuples_fetched++;		\
	} while (0)
#define pgstat_count_index_scan(rel)								\
	do {															\
		if (pgstat_should_count_relation(rel))						\
			(rel)->pgstat_info->t_counts.t_numscans++;				\
	} while (0)
#define pgstat_count_index_tuples(rel, n)							\
	do {															\
		if (pgstat_should_count_relation(rel))						\
			(rel)->pgstat_info->t_counts.t_tuples_returned += (n);	\
	} while (0)
#define pgstat_count_buffer_read(rel)								\
	do {															\
		if (pgstat_should_count_relation(rel))						\
			(rel)->pgstat_info->t_counts.t_blocks_fetched++;		\
	} while (0)
#define pgstat_count_buffer_hit(rel)								\
	do {															\
		if (pgstat_should_count_relation(rel))						\
			(rel)->pgstat_info->t_counts.t_blocks_hit++;			\
	} while (0)

extern void pgstat_count_heap_insert(Relation rel, PgStat_Counter n);
extern void pgstat_count_heap_update(Relation rel, bool hot);
extern void pgstat_count_heap_delete(Relation rel);
extern void pgstat_count_truncate(Relation rel);
extern void pgstat_update_heap_dead_tuples(Relation rel, int delta);

extern void pgstat_twophase_postcommit(TransactionId xid, uint16 info,
									   void *recdata, uint32 len);
extern void pgstat_twophase_postabort(TransactionId xid, uint16 info,
									  void *recdata, uint32 len);

extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry(Oid relid);
extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry_ext(bool shared,
														   Oid relid);
extern PgStat_TableStatus *find_tabstat_entry(Oid rel_id);


/*
 * pgstat_replslot.c中的函数
 */

extern void pgstat_reset_replslot(const char *name);
struct ReplicationSlot;
extern void pgstat_report_replslot(struct ReplicationSlot *slot, const PgStat_StatReplSlotEntry *repSlotStat);
extern void pgstat_create_replslot(struct ReplicationSlot *slot);
extern void pgstat_acquire_replslot(struct ReplicationSlot *slot);
extern void pgstat_drop_replslot(struct ReplicationSlot *slot);
extern PgStat_StatReplSlotEntry *pgstat_fetch_replslot(NameData slotname);


/*
 * pgstat_slru.c中的函数
 */

extern void pgstat_reset_slru(const char *);
extern void pgstat_count_slru_page_zeroed(int slru_idx);
extern void pgstat_count_slru_page_hit(int slru_idx);
extern void pgstat_count_slru_page_read(int slru_idx);
extern void pgstat_count_slru_page_written(int slru_idx);
extern void pgstat_count_slru_page_exists(int slru_idx);
extern void pgstat_count_slru_flush(int slru_idx);
extern void pgstat_count_slru_truncate(int slru_idx);
extern const char *pgstat_get_slru_name(int slru_idx);
extern int	pgstat_get_slru_index(const char *name);
extern PgStat_SLRUStats *pgstat_fetch_slru(void);


/*
 * pgstat_subscription.c中的函数
 */

extern void pgstat_report_subscription_error(Oid subid, bool is_apply_error);
extern void pgstat_create_subscription(Oid subid);
extern void pgstat_drop_subscription(Oid subid);
extern PgStat_StatSubEntry *pgstat_fetch_stat_subscription(Oid subid);


/*
 * pgstat_xact.c中的函数
 */

extern void AtEOXact_PgStat(bool isCommit, bool parallel);
extern void AtEOSubXact_PgStat(bool isCommit, int nestDepth);
extern void AtPrepare_PgStat(void);
extern void PostPrepare_PgStat(void);
struct xl_xact_stats_item;
extern int	pgstat_get_transactional_drops(bool isCommit, struct xl_xact_stats_item **items);
extern void pgstat_execute_transactional_drops(int ndrops, struct xl_xact_stats_item *items, bool is_redo);


/*
 * pgstat_wal.c中的函数
 */

extern void pgstat_report_wal(bool force);
extern PgStat_WalStats *pgstat_fetch_stat_wal(void);


/*
 * pgstat.c中的变量
 */

/* GUC 参数 */
extern PGDLLIMPORT bool pgstat_track_counts;
extern PGDLLIMPORT int pgstat_track_functions;
extern PGDLLIMPORT int pgstat_fetch_consistency;


/*
 * pgstat_bgwriter.c中的变量
 */

/* 由bgwriter和bufmgr直接更新 */
extern PGDLLIMPORT PgStat_BgWriterStats PendingBgWriterStats;


/*
 * pgstat_checkpointer.c中的变量
 */

/*
 * 检查点统计计数器由检查点器和bufmgr直接更新。
 */
extern PGDLLIMPORT PgStat_CheckpointerStats PendingCheckpointerStats;


/*
 * pgstat_database.c中的变量
 */

/* 由pgstat_count_buffer_*_time宏更新 */
extern PGDLLIMPORT PgStat_Counter pgStatBlockReadTime;
extern PGDLLIMPORT PgStat_Counter pgStatBlockWriteTime;

/*
 * 由pgstat_count_conn_*_time宏更新，调用于
 * pgstat_report_activity()。
 */
extern PGDLLIMPORT PgStat_Counter pgStatActiveTime;
extern PGDLLIMPORT PgStat_Counter pgStatTransactionIdleTime;

/* 由流量管理器和errfinish()更新 */
extern PGDLLIMPORT SessionEndType pgStatSessionEndCause;


/*
 * pgstat_wal.c中的变量
 */

/* 由后端和后台进程直接更新 */
extern PGDLLIMPORT PgStat_WalStats PendingWalStats;


#endif							/* PGSTAT_H */
